﻿using DotNetOpenAuth.AspNet;
using DotNetOpenAuth.AspNet.Clients;
using Newtonsoft.Json.Linq;
using RestSharp;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Text;
using System.Web;

namespace StockTradier.App_Start
{
    public class TradierOpenClient : OAuth2Client
    {

        private const string AuthorizationEndpoint = "https://api.tradier.com/v1/oauth/authorize";

        protected string ConsumerKey
        {
            get { return ConfigurationManager.AppSettings["ConsumerKey"] ?? string.Empty; }
        }

        protected string ConsumerSecret
        {
            get { return ConfigurationManager.AppSettings["ConsumerSecret"] ?? string.Empty; }
        }

        public TradierOpenClient()
            : base("Tradier")
        {

        }


        protected override Uri GetServiceLoginUrl(Uri returnUrl)
        {
            StringBuilder serviceUrl = new StringBuilder();

            serviceUrl.AppendFormat("{0}?client_id={1}", AuthorizationEndpoint, ConsumerKey);
            serviceUrl.Append("&scope=read&state="+Guid.NewGuid());

            return new Uri(serviceUrl.ToString());
        }

        protected override IDictionary<string, string> GetUserData(string accessToken)
        {
            IDictionary<String, String> extraData = new Dictionary<String, String>();

            RestClient client = new RestClient("https://api.tradier.com");
            var request = new RestRequest("/v1/user/profile", Method.GET);

            request.AddHeader("Authorization", "Bearer " + accessToken);
            var result = (client.Execute(request).Content);
            var json = JObject.Parse(result);


            var response = client.Execute(request);
            if (null != response.ErrorException)
            {
                return null;
            }
            else
            {
                string name = (string)json["profile"]["name"];
                extraData.Add("name", name);
                string id = (string)json["profile"]["id"];
                extraData.Add("id", id);
                string accountNumber = (string)json["profile"]["account"]["account_number"];
                extraData.Add("accountNumber", accountNumber);
                return extraData;
            }
        }

        protected override string QueryAccessToken(Uri returnUrl, string authorizationCode)
        {
            string accessToken = "";
            try
            {

                RestClient client = new RestClient("https://api.tradier.com");
                var request = new RestRequest("/v1/oauth/accesstoken", Method.POST);

                var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(string.Format("{0}:{1}", ConsumerKey, ConsumerSecret));
                string authorization = Convert.ToBase64String(plainTextBytes);

                request.AddHeader("Content-type", "application/x-www-form-urlencoded");
                request.AddHeader("Authorization", authorization);

                request.AddParameter("code", authorizationCode);
                request.AddParameter("grant_type", "authorization_code");

                var result = (client.Execute(request).Content);
                var json = JObject.Parse(result);

                accessToken = (string)json["access_token"];

                return accessToken;
            }
            catch (Exception ex)
            {
                return null;
            }
        }

        public override AuthenticationResult VerifyAuthentication(HttpContextBase context, Uri returnPageUrl)
        {

            string code = context.Request.QueryString["code"];
            if (string.IsNullOrEmpty(code))
            {
                return AuthenticationResult.Failed;
            }

            string accessToken = this.QueryAccessToken(returnPageUrl, code);
            if (accessToken == null)
            {
                return AuthenticationResult.Failed;
            }

            IDictionary<string, string> userData = this.GetUserData(accessToken);
            if (userData == null)
            {
                return AuthenticationResult.Failed;
            }

            string id = userData["id"];
            string name;

            // Some oAuth providers do not return value for the 'username' attribute. 
            // In that case, try the 'name' attribute. If it's still unavailable, fall back to 'id'
            if (!userData.TryGetValue("username", out name) && !userData.TryGetValue("name", out name))
            {
                name = id;
            }

            // add the access token to the user data dictionary just in case page developers want to use it
            userData["accesstoken"] = accessToken;

            return new AuthenticationResult(
                isSuccessful: true, provider: this.ProviderName, providerUserId: id, userName: name, extraData: userData);
        }
    }
}